#!/usr/bin/env python
"测试multiprocessing的共享内存"


import os
from multiprocessing import Process, Value, Array


NUMS_PROC_INT = 3  # 每个进程各自的全局对象，并非共享
COUNT_INT = 0


def show_data(label_str, value, array):
	"打印数据"
	msg = '{}: pid={} global={} value={} array={}'.format(
		label_str, os.getpid(), COUNT_INT, value.value, list(array)
	)
	print(msg)


def updater(value, array):
	"更新数据"
	global COUNT_INT
	COUNT_INT += 1  # 全局计数器，非共享
	value.value += 1  # 传入的对象是共享的
	for i_index_int in range(NUMS_PROC_INT):
		array[i_index_int] += 1


def main():
	global COUNT_INT
	value = Value('i', 0)  # 共享内存是进程、线程安全的
	array = Array('d', NUMS_PROC_INT)  # ctypes中的类型代码：就像int和double
	show_data('parent start', value, array)  # 在父进程中显示初始值

	# 派生子进程，传入共享内存
	process = Process(target=show_data, args=('child', value, array))
	process.start()
	process.join()

	# 传入父进程中更新过的共享内存，等待每次进程结束
	# 每个子进程看到了父进程到现在为止对args的更新（但全局变量看不到）
	print('\nloop 1 (updates in parent, serial children)...')
	for i_int in range(NUMS_PROC_INT):
		COUNT_INT += 1
		value.value += 1
		array[i_int] += 1
		process = Process(
			target=show_data, args=('process {}'.format(i_int), value, array)
		)
		process.start()
		process.join()

	# 同上，不过允许所有子进程并行运行
	# 所有进程都看到了最近一次迭代的结果，因为它们都共享这个对象
	print('\nloop 2 (updates in parent, parallel children)...')
	listprocess = []
	for i_int in range(NUMS_PROC_INT):
		COUNT_INT += 1
		value.value += 1
		array[i_int] += 1
		process = Process(
			target=show_data, args=('process {}'.format(i_int), value, array)
		)
		process.start()
		listprocess.append(process)
	for process in listprocess:
		process.join()

	# 共享内存在派生子进程中进行更新，等待每个更新结束
	print('\nloop 3 (updates in serial children)...')
	for i_int in range(NUMS_PROC_INT):
		process = Process(target=updater, args=(value, array))
		process.start()
		process.join()
	show_data('parent temp', value, array)  # 仅在父进程中全局变量COUNT_INT=6

	# 同上，不过允许子进程并行的更新
	print('\nloop 4 (updates in parallel children)...')
	listprocess = []
	for i_int in range(NUMS_PROC_INT):
		process = Process(target=updater, args=(value, array))
		process.start()
		listprocess.append(process)
	for process in listprocess:
		process.join()
	show_data('parent temp', value, array)  # 在此打印最终结果
	# value=12：父进程+6，6个子进程+6
	# array=[8.0, 8.0, 8.0]：父进程+2，6个子进程+6


if __name__ == '__main__':
	main()
